#include "include/blk.h"
#include "include/hvc.h"
#include "include/ivc.h"

#define DEV_C_BLK 0
#define MED_BLK_NUM 16

struct mediated_blk mediated_blk_list[MED_BLK_NUM];
u16 med_blk_num = 0;

bool mediated_blk_append(u64 cfg_user_addr) {
    u16 idx;

    struct mediated_blk_cfg cfg;
    if (copy_from_user(&cfg, (void *)cfg_user_addr,
                       sizeof(struct mediated_blk_cfg))) {
        WARNING("%s: copy from user failed", __func__);
        return false;
    }

    idx = cfg.idx;
    memcpy((void *)&mediated_blk_list[idx].cfg, (void *)&cfg,
           sizeof(struct mediated_blk_cfg));

    hvc_call(DEV_C_BLK, kva2ipa((u64)&mediated_blk_list[idx]), 0, 0, 0, 0, 0,
             HVC_MODE(HVC_MEDIATED, HVC_MEDIATED_DEV_APPEND));

    if (copy_to_user((void *)cfg_user_addr, (void *)&mediated_blk_list[idx].cfg,
                     sizeof(struct mediated_blk_cfg))) {
        WARNING("%s: copy to user failed", __func__);
        return false;
    }

    med_blk_num++;

    return true;
}

bool mediated_blk_notify(u16 blk_id) {
    struct mediated_blk *mediated_blk = &mediated_blk_list[blk_id];

    // INFO("%s: blk_id %d med_blk_ipa 0x%16x\n", __func__, blk_id,
    //        kva2ipa(mediated_blk));

    hvc_call(kva2ipa((u64)mediated_blk), 0, 0, 0, 0, 0, 0,
             HVC_MODE(HVC_MEDIATED, HVC_MEDIATED_DEV_NOTIFY));

    return true;
}

int mediated_blk_daemon_send_req(void) {
    int i;
    struct {
        u64 hvc_fid;
        u64 event;
        u16 blk_id;
        u32 type;
        u64 sector;
        u64 count;
    } usr_arg;

    for (i = 0; i < med_blk_num; i++) {
        struct mediated_blk *mediated_blk = &mediated_blk_list[i];
        if (mediated_blk->nreq == 0) {
            continue;
        }
        usr_arg.hvc_fid = HVC_MEDIATED;
        usr_arg.event = HVC_MEDIATED_USER_NOTIFY;
        usr_arg.blk_id = mediated_blk->cfg.idx;
        usr_arg.type = mediated_blk->req.type;
        usr_arg.sector = mediated_blk->req.sector;
        usr_arg.count = mediated_blk->req.count;

        // INFO("%s: blk_id %d type %d sector %d count %d\n", __func__,
        //        usr_arg.blk_id, usr_arg.type, usr_arg.sector, usr_arg.count);

        queue_push(shyper_dev.usr_arg_queue, &usr_arg, sizeof(usr_arg));

        mediated_blk->nreq--;
    }

    send_signal(SIGIVC);

    return 0;
}